"""
 @Author: xiangwuxiao
 @Email: xiangwuxiao@tencent.com
 @FileName: 扩容打包.py
 @DateTime: 2024/8/5 14:45
"""
import datetime
import os
import sys
import xml.etree.ElementTree as ET


def _now(format="%Y-%m-%d %H:%M:%S"):
    return datetime.datetime.now().strftime(format)


##### 可在脚本开始运行时调用，打印当时的时间戳及PID。
def job_start():
    print("[%s][PID:%s] job_start" % (_now(), os.getpid()))
    sys.stdout.flush()


##### 可在脚本执行成功的逻辑分支处调用，打印当时的时间戳及PID。
def job_success(msg):
    print("[%s][PID:%s] job_success:[%s]" % (_now(), os.getpid(), msg))
    sys.stdout.flush()
    sys.exit(0)


##### 可在脚本执行失败的逻辑分支处调用，打印当时的时间戳及PID。
def job_fail(msg):
    print("[%s][PID:%s] job_fail:[%s]" % (_now(), os.getpid(), msg))
    sys.stdout.flush()
    sys.exit(1)


class XmlParser:
    def __init__(self, filepath, fileType) -> None:
        self.filepath = filepath
        self.mytree = ET.parse(self.filepath)
        self.myroot = self.mytree.getroot()
        self.filetype = fileType
        self.check_file()

    def check_file(self):
        success = False
        CheckTag = ""
        if self.filetype == "host":
            CheckTag = "HostTab"
        elif self.filetype == "proc":
            CheckTag = "cluster"
        elif self.filetype == "proc_deploy":
            CheckTag = "ClusterDeploy"
        elif self.filetype == "bus_relation":
            CheckTag = "TbusConf"
        else:
            raise Exception("unsuport type: %s" % (self.filetype))

        for i in self.myroot:
            if i.tag == CheckTag:
                success = True
                break

        if not success:
            raise Exception("not found type: %s tag: %s" % (self.filetype, CheckTag))


class ProcParser(XmlParser):
    def __init__(self, filepath) -> None:
        super().__init__(filepath, "proc")
        self.cluster_node = self.get_cluster_node()
        self.world_node = self.get_world_node()

    def get_cluster_node(self):
        return self.myroot.find("cluster")

    def get_world_node(self):
        return self.myroot.find("cluster/world")

    def get_proc_group(self, name):
        for i in self.myroot:
            if i.tag == "ProcGroup" and i.attrib.get("Name") == name:
                return i
        raise Exception("can not found proc_group: %s" % (name))

    def get_proc_funcname(self, funcid):
        for i in self.world_node:
            funcname = i.attrib.get("FuncName")
            _funcid = i.attrib.get("FuncID")
            if i.tag == "Proc" and funcid == _funcid:
                print("instid %s get funcname %s" % (funcid, funcname))
                return funcname

        raise Exception("get func id %s funcname failed" % (funcid))

    def get_proc_name_belong_group_name(self, proc_name):
        for i in self.myroot:
            if i.tag == "ProcGroup":
                for j in i:
                    if j.tag == "Proc" and j.attrib.get("FuncName") == proc_name:
                        return i.attrib.get("Name")
        raise Exception("can not found proc_name %s belong to which group_name" % (proc_name))

    def get_proc_group_func_names(self, name):
        proc_group = self.get_proc_group(name)
        func_names = []
        for node in proc_group:
            if node.tag == "Proc":
                func_names.append(node.attrib.get("FuncName"))
        return func_names

    def get_funcname_instid(self, *names):
        # 返回funcname对应的id列表，一定按顺序返回回去
        if len(names) == 0:
            return {}

        m = {}
        for i in self.world_node:
            funcname = i.attrib.get("FuncName")
            instid = i.attrib.get("FuncID")
            if i.tag == "Proc" and funcname in names:
                print("funcname %s get instid %s" % (funcname, instid))
                m[funcname] = int(instid)

        if len(names) != len(m):
            raise Exception("names num %d not match instids num %d, names: %s" % (len(names), len(m), str(names)))
        return m


def get_scale_func_names(svcs):
    px = ProcParser("/data/home/user00/apps/tcm/cfg/proc.xml")
    func_names = []
    funcs = []
    for svc in svcs.split(","):
        svc = svc.strip()
        func_names += px.get_proc_group_func_names(svc)
        funcs += px.get_proc_group(svc)
    print("get funcs: %s" % (func_names))
    return func_names, funcs


def get_pkg_dirs(scale_deploygroup_names):
    func_names, funcs = get_scale_func_names(scale_deploygroup_names)
    pkg_dirs = set()
    pkg_dirs.add("osgame/tool")
    # 公共包获取
    for svc in func_names:
        if svc in ["aiclientsvr", "gamecoresvr"]:
            pkg_dirs.add("osgame/bin/gamecorelib")
        if svc in ["gamesvr", "auxsvr", "infosvr", "lineupsvr"]:
            pkg_dirs.add("osgame/bin/lib")
        if svc == "lssvr":
            pkg_dirs.add("osgame/bin/tool")
    if "aiclientsvr" not in func_names and "gamecoresvr" not in func_names:
        pkg_dirs.add("osgame/bin/protobufdatabin")
    if "gamecoresvr" not in func_names:
        pkg_dirs.add("osgame/bin/sidecar")
    # 进程包获取
    for node in funcs:
        if node.tag == "Proc":
            workpath = node.attrib.get("WorkPath")
            if not workpath:
                raise Exception("get node %s workpath failed" % (node))
            pkg_dirs.add(workpath)
    print("get pkg dirs: %s" % (pkg_dirs))
    return pkg_dirs


if __name__ == '__main__':
    if len(sys.argv) != 3:
        job_fail("params failed, usage: %s pkg_name scale_deploygroup_names" % (sys.argv[0]))
    pkg_name = sys.argv[1].strip()
    scale_deploygroup_names = sys.argv[2].strip()
    if pkg_name == "" or scale_deploygroup_names == "":
        job_fail("params failed, usage: %s pkg_name scale_deploygroup_names" % (sys.argv[0]))

    job_start()
    pkg_dirs = get_pkg_dirs(scale_deploygroup_names)

    dirpath = "/data/home/user00/backup/"
    if not os.path.exists(dirpath):
        os.makedirs(dirpath)

    os.chdir("/data/home/user00")
    cmd = "tar zcf %s%s %s" % (dirpath, pkg_name, " ".join(pkg_dirs))
    print("start execute cmd: %s" % (cmd))
    sys.stdout.flush()
    os.system(cmd)
    print("execute pkg success")
